
__author__ = "Andrew Ostler <os@collective.co.uk>"

import sys, datetime, time, socket, threading
from telnetlib import Telnet
from audioscrobbler import AudioScrobblerPost
from audioscrobbler import AudioScrobblerError
from Zeroconf import *

class ZeroconfListener(object):
	def __init__(self):
		self.z = Zeroconf()
		pass

	def removeService(self, zeroconf, type, name):
		print "Service", name, "removed"
		lock.acquire()
		if soundbridges.has_key( name ):
			print 'Removing Soundbridge', name
			del soundbridges[ name ]
		lock.release()

	def addService(self, zeroconf, type, name):
		print "Service", name, "added"
		info = self.z.getServiceInfo(type, name)
		props = info.getProperties()
		if props.has_key( 'path' ) and props[ 'path' ] == '/SoundBridge.html':
			address = str(socket.inet_ntoa(info.getAddress()))
			soundbridge = { 'address':address, 'current':{}, 'starttime':None, 'submitted':False, 'length':0 }

			tn = Telnet( soundbridge['address'], 5555 )

			response = tn.read_until( "roku: ready", 5 )
			if response != "roku: ready":
				print( "no roku: ready: ", response )
				return
				
			tn.write( "GetFriendlyName\n" )
			friendlyname = tn.read_until( "GetFriendlyName: ", 5 )
			friendlyname = tn.read_until( "\r\n", 5 )
			tn.close()
			friendlyname = friendlyname[:-2]
			
			soundbridge['friendlyname'] = friendlyname

			print 'Adding Soundbridge "%s" at %s' % ( friendlyname, address )

			lock.acquire()
			soundbridges[ name ] = soundbridge
			lock.release()

def DoIt():
	while True:
		lock.acquire()
		for name, soundbridge in soundbridges.iteritems():
			try:
				tn = Telnet( soundbridge['address'], 5555 )

				response = tn.read_until( "roku: ready", 5 )
				if response != "roku: ready":
					print( "no roku: ready: ", response )
					continue
					
				tn.write( "GetCurrentSongInfo\n" )

				response = tn.read_until( "GetCurrentSongInfo: OK", 5 )
				lines = response.split( "\r\n" )
				info = {}
				for line in lines:
					line = line[20:]
					bits = line.split( ': ' )
					if len(bits) == 2:
						info[ bits[0] ] = bits[1]

				tn.close()
			except KeyboardInterrupt:
				pass
			except:
				print 'unable to get status from', soundbridge['friendlyname'], 'at', soundbridge['address']
				continue
			
			if not info.has_key( 'album' ):
				info[ 'album' ] = ''

			if info != soundbridge['current']:

				now = datetime.datetime.utcnow()
				print now.replace( microsecond=0 ).isoformat( ' ' ), ': new track for', soundbridge['friendlyname']
				print "info:", info
				soundbridge['current'] = info
				soundbridge['starttime'] = now
				soundbridge['submitted'] = False
				soundbridge['subtime'] = 240
				if not info.has_key( 'artist' ) or not info.has_key( 'title' ) or not info.has_key( 'trackLengthMS' ):
					soundbridge['submitted'] = True
					print 'required keys not present'
					continue
				length = eval( info[ 'trackLengthMS' ] ) / 1000
				if length < 30:
					soundbridge['submitted'] = True
					print 'too short:', length
					continue
				soundbridge[ 'length' ] = length
				if length < 480:
					soundbridge['subtime'] = length/2
				
				continue
				
			if soundbridge['submitted']:
				continue

			now = datetime.datetime.utcnow()
			playtime = ( now - soundbridge['starttime'] ).seconds
			print "%s %ds : %s : %s : %s" % ( soundbridge['friendlyname'], playtime, info[ 'artist' ], info[ 'title' ], info[ 'album' ] )
			if playtime < soundbridge['subtime']:
				continue

			track = {}
			track[ 'artist_name' ] = info[ 'artist' ]
			track[ 'song_title' ] = info[ 'title' ]
			track[ 'length' ] = soundbridge[ 'length' ]
			track[ 'album' ] = info[ 'album' ]
			track[ 'date_played' ] = soundbridge['starttime'].replace( microsecond=0 ).isoformat( ' ' )
			
			print "submitting:", track

			try:
				post(**track)
			except AudioScrobblerError, error:
				print 'post failed with AudioScrobblerError:', error
			except KeyboardInterrupt:
				pass
			except Exception, error:
				print 'post failed:', error

			soundbridge['submitted'] = True

		lock.release()
			
		time.sleep( 15 )

soundbridges = {}

username = None
password = None
for arg in sys.argv[1:]:
	bits = arg.split( '=' )
	if len(bits) == 2:
		if bits[0] == 'username':
			username = bits[1]
		elif bits[0] == 'password':
			password = bits[1]
if username == None or password == None:
	raise Exception, 'please specify username and password'
post = AudioScrobblerPost( username=username, password=password, verbose=True )

lock = threading.Lock()

try:
	z = Zeroconf()
	type = "_http._tcp.local."
	listener = ZeroconfListener()
	browser = ServiceBrowser( z, type, listener )

	DoIt()
	
finally:
	print 'shutting down Zeroconf'
	browser.cancel()
	z.close()
